package com.asa.a;

/**
 * 堆的东西太多了
 * 
 * @author Administrator
 *
 */
public class II {

	/**
	 * 堆是分配对象存储的唯一选择吗?
			在《深入理解Java虚拟机》中关于Java堆内存有这样一段描述:
			随着JIT编译期的发展与逃逸分析技术逐渐成熟，栈上分配、标量替换优化技术将会导
			致一些微妙的变化，所有的对象都分配到堆上也渐渐变得不那么“绝对”了。
			在Java虚拟机中，对象是在Java堆中分配内存的，这是一个普遍的常识。但是，有一
			种特殊情况，那就是如果经过逃逸分析(Escape Analysis) 后发现，一个对象并没有
			逃逸出方法的话，那么就可能被优化成栈上分配。这样就无需在堆上分配内存，也无须
			进行垃圾回收了。这也是最常见的堆外存储技术。
			此外，前面提到的基于OpenJDK深度定制的TaoBaoVM，其中创新的GCIH (GC
			invisible heap) 技术实现off -heap，将生命周期较长的Java对象从heap中移至
			heap外，并且GC不能管理GCIH内部的Java对象，以此达到降低Gc的回收频率和提升
			GC的回收效率的目的。

	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 参数设置:
				●在JDK 6u23版本之后，HotSpot中默认就已经开启了逃逸分析。
				●如果使用的是较早的版本，开发人员则可以通过:
				➢选项“-XX: +DoEscapeAnalysis"显式开启逃逸分析
				➢通过选项“-XX: +PrintEscapeAnalysis"查看逃逸分析的筛
				选结果。

	 * 
	 * 
	 * 
	 * 
	 * 使用逃逸分析，编译器可以对代码做如下优化:
			一、栈上分配将堆分配转化为栈分配。如果一个对象在子程序中被分配，
			要使指向该对象的指针永远不会逃逸，对象可能是栈分配的候选，而不是堆
			分配。				本质上来说，它是通过将对象放到栈中来实现的，因为这些对象是随着栈的消亡而消亡，所以可以这么写（这个其实用得比较少，技术不成熟没有广泛使用，第三点用得多）
			二、同步省略。如果一个对象被发现只能从一个线程被访问到，那么对于这
			个对象的操作可以不考虑同步。		本质上来说，它判断当前线程中加的锁是否必要，它在编译的时候没有优化，它是JIT即时编译优化的（JIT也会耗点性能）
			三、分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存
			在也可以被访问到，那么对象的部分(或全部)可以不存储在内存，而是存
			储在CPU寄存器中。			本质上来说，对象不被外部调用，那么对象的属性（基本数据类型）就可以被优化为局部变量来使用，这些变量都在栈上

	 * 
	 * JIT编译器在编译期间根据逃逸分析的结果，发现如果一个对象并没有逃 
			逸出方法的话，就可能被优化成栈上分配。分配完成后，继续在调用栈内
			执行，最后线程结束，栈空间被回收，局部变量对象也被回收。这样就无
			须进行垃圾回收了。
			常见的栈上分配的场景
			➢在逃逸分析中，已经说明了。分别是给成员变量赋值、方法返回值、
			实例引用传递。

	 * 
	 * 
	 * 代码优化之同步省略(消除)
			线程同步的代价是相当高的，同步的后果是降低并发性和性能。
			在动态编译同步块的时候，JIT编译器可以借助逃逸分析来判断同步块所
			使用的锁对象是否只能够被一个线程访问而没有被发布到其他线程。如果
			没有，那么JIT编译器在编译这个同步块的时候就会取消对这部分代码的
			同步。这样就能大大提高并发性和性能。这个取消同步的过程就叫同步省
			略，也叫锁消除。

	 * 
	 * 
	 * 
	 * 
	 * 代码优化之标量替换
			标量(Scalar)是指一个无法再分解成更小的数据的数据。Java中的原始数据类型就是标量。
			相对的，那些还可以分解的数据叫做聚合量(Aggregate)，Java中的对象就是聚合量，因
			为他可以分解成其他聚合量和标量。
			在JIT阶段，如果经过逃逸分析，发现一个对象不会被外界访问的话，那么经过JIT优化，就
			会把这个对象拆解成若干个其中包含的若干个成员变量来代替。这个过程就是标量替换。

	 * 
	 * 标量替换参数设置:
		参数-XX: +EliminateAllocations:开启了标量替换(默认打开)，允许将对象打散分配在栈上。


	 * 参数-server:启动Server模式， 因为在Server模式下，才可以启用逃逸分析。

	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 
	 * 逃逸分析小结:逃逸分析并不成熟@>
			●关于逃逸分析的论文在1999年就已经发表了，但直到JDK 1.6才有实现，而且这项技
			术到如今也并不是十分成熟的。|
			其根本原因就是无法保证逃逸分析的性能消耗--定能高于他的消耗。虽然经过逃逸分
			析可以做标量替换、栈上分配、和锁消除。但是逃逸分析自身也是需要进行一系列复
			杂的分析的，这其实也是一个相对耗时的过程。
			●-一个极端的例子，就是经过逃逸分析之后，发现没有一个对象是不逃逸的。那这个逃
			逸分析的过程就白白浪费掉了。
			虽然这项技术并不十分成熟，但是它也是即时编译器优化技术中一个十分重要的手段。
			注意到有一-些观点，认为通过逃逸分析，JVM会在栈上分配那些不会逃逸的对象，这
			在理论上是可行的，但是取决于JVM设计者的选择。据我所知，Oracle Hotspot
			JVM中并未这么做，这一点在逃逸分析相关的文档里已经说明，所以可以明确所有的
			对象实例都是创建在堆上。
			目前很多书籍还是基于JDK 7以前的版本，JDK已经发生了很大变化，intern字符串
			的缓存和静态变量曾经都被分配在永久代上，而永久代已经被元数据区取代。但是，
			intern字符串缓存和静态变量并不是被转移到元数据区，而是直接在堆上分配，所以
			这一点同样符合前面一.点的结论:对象实例都是分配在堆上。


	 * 
	 * 
	 * 
	 * 年轻代是对象的诞生、成长、消亡的区域，一个对象在这里产生、应用，
			最后被垃圾回收器收集、结束生命。
			老年代放置长生命周期的对象，通常都是从Survivor区域筛选拷贝过来的
			Java对象。当然，也有特殊情况，我们知道普通的对象会被分配在TLAB上:
			如果对象较大，JVM会 试图直接分配在Eden其他位置上;如果对象太大，
			完全无法在新生代找到足够长的连续空闲空间，JVM就会直接分配到老年代
			当GC只发生在年轻代中，回收年轻代对象的行为被称为MinorGC。当GC
			发生在老年代时则被称为MajorGC或者FullGC。一般的，MinorGC的
			发生频率要比MajorGC高很多，即老年代中垃圾回收发生的频率将大大低
			于年轻代。

	 * 
	 * 
	 * 
	 * 


	 * 
	 * 
	 */
	
	
	
	
}
